class Fragment {
    raw : any;
    values : any [];
    constructor (text : any, values : any []) {
        this.raw = text;
        this.values = values;
    }
}
function cond (k : string, v : any, chain : any) : any {
    let type : string = typeof v;
    if (Array.isArray (v) && v.length == 0) return chain ([], "FALSE");
    if (type == "object") return chain ([], `${k} IS${v === null ? '' : ' NOT'} NULL`);
    if (type == "boolean") return chain ([], '%sNOT(%s)');
    return chain ([v], '%s=?:');
}
function merge (vals : any, operator : string, chain : any) : any {
    let conds : any [] = [];
    let data : any [] = [];
    vals.forEach (function (val : any) : void {
        where (val, function (vals : any, txt : any) : void {
            data.push.apply (data, vals);
            conds.push (txt);
        });
    });
    return chain (data, conds.length == 1 ? conds [0] : '(' + conds.join (operator) + ')');
}
function where (vals : any, chain : any) : any {
    let type : string = typeof vals;
    if (vals instanceof Fragment) return chain (vals.values, vals.raw);
    if (Array.isArray (vals) && vals.length == 0 || vals === undefined || vals === null) return chain ([], "FALSE");
    if (type == "boolean") return chain ([], vals ? "TRUE" : "FALSE");
    if (Array.isArray (vals)) return merge (vals, ' AND ', chain);
    if (type == "object") {
        let conds : any [] = [];
        let data : any [] = [];
        for (let k in vals) {
            cond (k, vals [k], function (vals : any, txt : any) : void {
                data.push.apply (data, vals);
                conds.push (txt);
            });
        }
        return chain (data, conds.join (' AND '));
    }
    return chain ([], vals);
}
console.log (where (true, function (data : any, txt : any) : void {
    data + `a WHERE ${txt}`;
}))
const values : any [] = [];
values.push ("banana", "apple", "peach");
console.log (merge (values, 'and', function (data : any, txt : any) : void {
    data + `a WHERE ${txt}`;
}))
console.log (cond ('a', values, function (data : any, txt : any) : void {
    data + `a WHERE ${txt}`;
}))
